#include <sys/epoll.h>
#include "wrap.h"

/**
 * 多路 IO 转接（多路IO服用）：内核监听多个文件描述符的属性（读写缓冲区）变化
 * 如果某个文件描述符的读缓冲区变化了，就可以进行读操作为了。会将这个事件告诉应用层。
 *      select      Windows平台使用select，跨平台
 *      epoll       Linux
 *      poll        很少使用
 * @return
 */
//int main(int argc,char * argv[]) {return 1;}

#define PORT 8080


/**
 * select
 *      优点
 *          跨平台
 *      缺点
 *          文件描述符的限制 1024 由于FD_SETSIZE的限制
 *          只是返回变化的文件描述符的个数，具体的变化需要遍历
 *          每次都需要将需要监听的文件描述符给到内核
 *          大量并发，少量活跃，select效率低
 *      可以使用 dup2 对某个文件描述符进行重定向。然后关闭某个文件描述符
 *
 * poll
 *      优点
 *          相对于select 没有 1024文件描述符限制 ulimit cat /proc/sys/fs/file-max
 *          请求和返回时分离的
 *      缺点 基本和select 一样
 *          每次 都需要将文件描述符拷贝到内核
 *          每次都需要将数组中的元素都遍历一次
 *          大量并发，少量活跃时效率太低
 *
 * epoll
 *      工作原理
 *          1 创建红黑树             epoll_create
 *          2 数据上树 下树 修改节点   epoll_ctl
 *          3 监听                  epoll_wait
 *      优点
 *          没有文件描述符 个数限制
 *          以后每次监听都不要再将监听的描述符拷贝到内核中了
 *          返回的是已经变化的文件描述符，不需要遍历整个 红黑树
 *      缺点
 *
 * @param argc
 * @param argv
 * @return
 */
int main(int argc,char * argv[]) {
    int fds[2];
    pipe(fds);

    pid_t pid;
    pid = fork();
    //创建子进程失败
    if(pid < 0){
        perror("fork");
    }
    else if(pid == 0){
        close(fds[0]);
        char buf[5];
        char cc = 'a';
        while (1) {
            memset(buf,cc++, sizeof(buf));
            write(fds[1],buf,5);
            sleep(3);
        }
    }
    else{
        close(fds[1]);
        // 创建树
        int epfd = epoll_create(1);
        struct epoll_event epollEvent, epollEvents[1];
        epollEvent.data.fd = fds[0];
        epollEvent.events = EPOLLIN;
        // 进树
        epoll_ctl(epfd,EPOLL_CTL_ADD,fds[0],&epollEvent);
        while (1) {
            // 监听
            int n = epoll_wait(epfd,epollEvents,1,-1);
            if(n == 1){
                char buff[128] = "";
                int ret = read(fds[0],buff, sizeof(buff));
                if(ret <= 0){
                    close(fds[0]);
                    epoll_ctl(epfd,EPOLL_CTL_DEL,fds[0],&epollEvent);
                    break;
                }
                else {
                    printf("%s \n",buff);
                }
            }
        }
    }
    return 1;
}

